home *** CD-ROM | disk | FTP | other *** search
- /* Keyboard input; editor command loop.
- Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
-
- This file is part of XEmacs.
-
- XEmacs is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any
- later version.
-
- XEmacs is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
-
- You should have received a copy of the GNU General Public License
- along with XEmacs; see the file COPYING. If not, write to the Free
- Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- /* Synched up with: Mule 2.0. Not synched with FSF. */
-
- #include <config.h>
- #include "lisp.h"
-
- #include "buffer.h"
- #include "commands.h"
- #include "device.h"
- #include "device-tty.h"
- #include "events.h"
- #include "frame.h"
- #include "macros.h"
- #include "sysdep.h"
- #include "window.h"
-
- #include <setjmp.h>
- #include <errno.h>
- #include "systime.h"
-
- Lisp_Object Qsuspend_hook;
- Lisp_Object Qsuspend_resume_hook;
-
- /* Current depth in recursive edits. */
- int command_loop_level;
-
- /* Total number of times command_loop has read a key sequence. */
- int num_input_keys;
-
- #ifndef LISP_COMMAND_LOOP
- /* Form to evaluate (if non-nil) when Emacs is started */
- Lisp_Object Vtop_level;
- #else
- /* Function to call to evaluate to read and process events */
- Lisp_Object Vcommand_loop;
- #endif /* LISP_COMMAND_LOOP */
-
- /* The error handler */
- Lisp_Object Qcommand_error;
-
- /* The emergency error handler, before we're ready */
- Lisp_Object Qreally_early_error_handler;
-
- /* File in which we write all commands we read */
- /* #### there is exactly zero chance that this works right now */
- static FILE *dribble;
-
- static Lisp_Object command_loop_1 (Lisp_Object dummy);
-
- /* There are two possible command loops -- one written entirely in
- C and one written mostly in Lisp, except stuff written in C for
- speed. The advantage of the Lisp command loop is that the user
- can specify their own command loop to use by changing the variable
- `command-loop'. Its disadvantage is that it's slow. */
-
- static Lisp_Object
- default_error_handler (Lisp_Object data)
- {
- int speccount = specpdl_depth ();
-
- Fding (Qnil, Qnil, Qnil);
- zmacs_deactivate_region ();
- Fdiscard_input ();
- specbind (Qinhibit_quit, Qt);
- Vstandard_output = Qt;
- Vstandard_input = Qt;
- Vexecuting_macro = Qnil;
- clear_echo_area (selected_frame (), Qnil, 0);
- data = Fprin1_to_string (data, Qnil);
- message ("Error: %s", string_data (XSTRING (data)));
- check_quit (); /* make Vquit_flag accurate */
- Vquit_flag = Qnil;
- return (unbind_to (speccount, Qt));
- }
-
- DEFUN ("really-early-error-handler", Freally_early_error_handler,
- Sreally_early_error_handler, 1, 1, 0,
- "You should almost certainly not be using this.")
- (x)
- Lisp_Object x;
- {
- /* This is an error handler used when we're running temacs and when
- we're in the early stages of XEmacs. No errors ought to be
- occurring in those cases (or they ought to be trapped and
- dealt with elsewhere), but if an error slips through, we need
- to deal with it. We could write this function in Lisp (and it
- used to be this way, at the beginning of loadup.el), but we do
- it this way in case an error occurs before we get to loading
- loadup.el. Note that there is also an `early-error-handler',
- used in startup.el to catch more reasonable errors that
- might occur during startup if the sysadmin or whoever fucked
- up. This function is more conservative in what it does
- and is used only as a last resort, indicating that the
- programmer himself fucked up somewhere. */
- stderr_out ("*** Error in XEmacs initialization");
- Fprint (x, Qexternal_debugging_output);
- stderr_out ("*** Backtrace\n");
- Fbacktrace (Qexternal_debugging_output, Qt);
- stderr_out ("*** Killing XEmacs\n");
- return Fkill_emacs (make_number (-1));
- }
-
-
- /**********************************************************************/
- /* Command-loop (in C) */
- /**********************************************************************/
-
- #ifndef LISP_COMMAND_LOOP
-
- /* The guts of the command loop are in command_loop_1(). This function
- doesn't catch errors, though -- that's the job of command_loop_2(),
- which is a condition-case wrapper around command_loop_1().
- command_loop_1() never returns, but may get thrown out of.
-
- When an error occurs, cmd_error() is called, which usually
- invokes the Lisp error handler in `command-error'; however,
- a default error handler is provided if `command-error' is nil
- (e.g. during startup). The purpose of the error handler is
- simply to display the error message and do associated cleanup;
- it does not need to throw anywhere. When the error handler
- finishes, the condition-case in command_loop_2() will finish and
- command_loop_2() will reinvoke command_loop_1().
-
- command_loop_2() is invoked from three places: from
- initial_command_loop() (called from main() at the end of
- internal initialization), from the Lisp function `recursive-edit',
- and from call_command_loop().
-
- call_command_loop() is called when a macro is started and when the
- minibuffer is entered; normal termination of the macro or
- minibuffer causes a throw out of the recursive command loop. (To
- 'execute-kbd-macro for macros and 'exit for minibuffers. Note also
- that the low-level minibuffer-entering function,
- `read-minibuffer-internal', provides its own error handling and
- does not need command_loop_2()'s error encapsulation; so it tells
- call_command_loop() to invoke command_loop_1() directly.)
-
- Note that both read-minibuffer-internal and recursive-edit set
- up a catch for 'exit; this is why `abort-recursive-edit', which
- throws to this catch, exits out of either one.
-
- initial_command_loop(), called from main(), sets up a catch
- for 'top-level when invoking command_loop_2(), allowing functions
- to throw all the way to the top level if they really need to.
- Before invoking command_loop_2(), initial_command_loop() calls
- top_level_1(), which handles all of the startup stuff (creating
- the initial frame, handling the command-line options, loading
- the user's .emacs file, etc.). The function that actually does this
- is in Lisp and is pointed to by the variable `top-level';
- normally this function is `normal-top-level'. top_level_1() is
- just an error-handling wrapper similar to command_loop_2().
- Note also that initial_command_loop() sets up a catch for 'top-level
- when invoking top_level_1(), just like when it invokes
- command_loop_2(). */
-
-
- static Lisp_Object
- cmd_error (Lisp_Object data, Lisp_Object dummy)
- {
- /* This function can GC */
- check_quit (); /* make Vquit_flag accurate */
- Vquit_flag = Qnil;
-
- if (!NILP (Ffboundp (Qcommand_error)))
- return call1 (Qcommand_error, data);
-
- return default_error_handler (data);
- }
-
- static Lisp_Object
- top_level_1 (Lisp_Object dummy)
- {
- /* This function can GC */
- /* On entry to the outer level, run the startup file */
- if (!NILP (Vtop_level))
- condition_case_1 (Qerror, Feval, Vtop_level, cmd_error, Qnil);
- #if 1
- else
- {
- message ("\ntemacs can only be run in -batch mode.");
- noninteractive = 1; /* prevent things under kill-emacs from blowing up */
- Fkill_emacs (make_number (-1));
- }
- #else
- else if (purify_flag)
- message ("Bare impure Emacs (standard Lisp code not loaded)");
- else
- message ("Bare Emacs (standard Lisp code not loaded)");
- #endif
-
- return Qnil;
- }
-
- /* Here we catch errors in execution of commands within the
- editing loop, and reenter the editing loop.
- When there is an error, cmd_error runs and the call
- to condition_case_1() returns. */
-
- static Lisp_Object
- command_loop_2 (Lisp_Object dummy)
- {
- /* This function can GC */
- for (;;)
- {
- condition_case_1 (Qerror, command_loop_1, Qnil, cmd_error, Qnil);
- }
-
- return Qnil; /* suppress warnings */
- }
-
- /* This is called from emacs.c when it's done with initialization. */
-
- DOESNT_RETURN
- initial_command_loop (Lisp_Object load_me)
- {
- /* This function can GC */
- if (!NILP (load_me))
- Vtop_level = list2 (Qload, load_me);
-
- /* First deal with startup and command-line arguments. A throw
- to 'top-level gets us back here directly (does this ever happen?).
- Otherwise, this function will return normally when all command-
- line arguments have been processed, the user's initialization
- file has been read in, and the first frame has been created. */
- internal_catch (Qtop_level, top_level_1, Qnil, 0);
-
- /* If an error occurred during startup and the initial device
- wasn't created, then die now (the error was already printed out
- on the terminal device). */
- if (!noninteractive &&
- (!DEVICEP (Fselected_device ()) ||
- DEVICE_IS_STREAM (XDEVICE (Fselected_device ()))))
- Fkill_emacs (make_number (-1));
-
- /* End of -batch run causes exit here. */
- if (noninteractive)
- Fkill_emacs (Qt);
-
- for (;;)
- {
- command_loop_level = 0;
- MARK_MODELINE_CHANGED;
- /* Now invoke the command loop. It never returns; however, a
- throw to 'top-level will place us at the end of this loop. */
- internal_catch (Qtop_level, command_loop_2, Qnil, 0);
- }
- }
-
- /* This function is invoked when a macro or minibuffer starts up.
- Normal termination of the macro or minibuffer causes a throw past us.
- See the comment above.
-
- Note that this function never returns (but may be thrown out of). */
-
- Lisp_Object
- call_command_loop (Lisp_Object catch_errors)
- {
- /* This function can GC */
- if (NILP (catch_errors))
- return (command_loop_1 (Qnil));
- else
- return (command_loop_2 (Qnil));
- }
-
- static Lisp_Object
- recursive_edit_unwind (Lisp_Object buffer)
- {
- if (!NILP (buffer))
- Fset_buffer (buffer);
-
- command_loop_level--;
- MARK_MODELINE_CHANGED;
-
- return Qnil;
- }
-
- DEFUN ("recursive-edit", Frecursive_edit, Srecursive_edit, 0, 0, "",
- "Invoke the editor command loop recursively.\n\
- To get out of the recursive edit, a command can do `(throw 'exit nil)';\n\
- that tells this function to return.\n\
- Alternately, `(throw 'exit t)' makes this function signal an error.")
- ()
- {
- /* This function can GC */
- Lisp_Object val;
- int speccount = specpdl_depth ();
-
- command_loop_level++;
- MARK_MODELINE_CHANGED;
-
- record_unwind_protect (recursive_edit_unwind,
- ((current_buffer
- != XBUFFER (XWINDOW (Fselected_window (Qnil))->buffer))
- ? Fcurrent_buffer ()
- : Qnil));
-
- specbind (Qstandard_output, Qt);
- specbind (Qstandard_input, Qt);
-
- val = internal_catch (Qexit, command_loop_2, Qnil, 0);
-
- if (EQ (val, Qt))
- /* Turn abort-recursive-edit into a quit. */
- Fsignal (Qquit, Qnil);
-
- return unbind_to (speccount, Qnil);
- }
-
- #endif /* !LISP_COMMAND_LOOP */
-
-
- /**********************************************************************/
- /* Alternate command-loop (largely in Lisp) */
- /**********************************************************************/
-
- #ifdef LISP_COMMAND_LOOP
-
- static Lisp_Object
- load1 (Lisp_Object name)
- {
- /* This function can GC */
- call4 (Qload, name, Qnil, Qt, Qnil);
- return (Qnil);
- }
-
- /* emergency backups for cold-load-stream use */
- static Lisp_Object
- cold_load_command_error (Lisp_Object datum, Lisp_Object ignored)
- {
- /* This function can GC */
- check_quit (); /* make Vquit_flag accurate */
- Vquit_flag = Qnil;
-
- return default_error_handler (datum);
- }
-
- static Lisp_Object
- cold_load_command_loop (Lisp_Object dummy)
- {
- /* This function can GC */
- return (condition_case_1 (Qt,
- command_loop_1, Qnil,
- cold_load_command_error, Qnil));
- }
-
- Lisp_Object
- call_command_loop (Lisp_Object catch_errors)
- {
- /* This function can GC */
- reset_this_command_keys (Qnil);
-
- loop:
- for (;;)
- {
- if (NILP (Vcommand_loop))
- break;
- call1 (Vcommand_loop, catch_errors);
- }
-
- /* This isn't a "correct" definition, but you're pretty hosed if
- you broke "command-loop" anyway */
- Vprefix_arg = Qnil;
- if (NILP (catch_errors))
- Fcommand_loop_1 ();
- else
- internal_catch (Qtop_level,
- cold_load_command_loop, Qnil, 0);
- goto loop;
- return Qnil;
- }
-
- static Lisp_Object
- initial_error_handler (Lisp_Object datum, Lisp_Object ignored)
- {
- /* This function can GC */
- Vcommand_loop = Qnil;
- Fding (Qnil, Qnil, Qnil);
-
- if (CONSP (datum) && EQ (XCAR (datum), Qquit))
- /* Don't bother with the message */
- return (Qt);
-
- message ("Error in command-loop!!");
- Fset (intern ("last-error"), datum); /* #### Better/different name? */
- Fsit_for (make_number (2), Qnil);
- cold_load_command_error (datum, Qnil);
- return (Qt);
- }
-
- DOESNT_RETURN
- initial_command_loop (Lisp_Object load_me)
- {
- /* This function can GC */
- if (!NILP (load_me))
- {
- if (!NILP (condition_case_1 (Qt, load1, load_me,
- initial_error_handler, Qnil)))
- Fkill_emacs (make_number (-1));
- }
-
- for (;;)
- {
- command_loop_level = 0;
- MARK_MODELINE_CHANGED;
-
- condition_case_1 (Qt,
- call_command_loop, Qtop_level,
- initial_error_handler, Qnil);
- }
- }
-
- #endif /* LISP_COMMAND_LOOP */
-
-
- /**********************************************************************/
- /* Guts of command loop */
- /**********************************************************************/
-
- static Lisp_Object
- command_loop_1 (Lisp_Object dummy)
- {
- /* This function can GC */
- Vprefix_arg = Qnil;
- return (Fcommand_loop_1 ());
- }
-
- /* This is the actual command reading loop, sans error-handling
- encapsulation. This is used for both the C and Lisp command
- loops. Originally this function was written in Lisp when
- the Lisp command loop was used, but it was too slow that way.
-
- Under the C command loop, this function will never return
- (although someone might throw past it). Under the Lisp
- command loop, this will return only when the user specifies
- a new command loop by changing the command-loop variable. */
-
- DEFUN ("command-loop-1", Fcommand_loop_1, Scommand_loop_1, 0, 0, 0,
- "Invoke the internals of the canonical editor command loop.\n\
- Don't call this unless you know what you're doing.")
- ()
- {
- /* This function can GC */
- Lisp_Object event = Fallocate_event ();
- Lisp_Object old_loop = Qnil;
- struct gcpro gcpro1, gcpro2;
- GCPRO2 (event, old_loop);
-
- /* cancel_echoing (); */
- /* This magically makes single character keyboard macros work just
- like the real thing. This is slightly bogus, but it's in here for
- compatibility with Emacs 18. It's not even clear what the "right
- thing" is. */
- if (!(((STRINGP (Vexecuting_macro) || VECTORP (Vexecuting_macro))
- && XINT (Flength (Vexecuting_macro)) == 1)))
- Vlast_command = Qt;
-
- #ifndef LISP_COMMAND_LOOP
- while (1)
- #else
- old_loop = Vcommand_loop;
- while (EQ (Vcommand_loop, old_loop))
- #endif /* LISP_COMMAND_LOOP */
- {
- /* Make sure the current window's buffer is selected. */
- {
- Lisp_Object selected_window = Fselected_window (Qnil);
-
- if (!NILP (selected_window) &&
- (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer))
- {
- set_buffer_internal (XBUFFER (XWINDOW (selected_window)->buffer));
- }
- }
-
- #if 0 /* NYI */
- /* Display any malloc warning that just came out. Use while because
- displaying one warning can cause another. */
- while (pending_malloc_warning)
- display_malloc_warning ();
- #endif
-
- /* If ^G was typed before we got here (that is, before emacs was
- idle and waiting for input) then we treat that as an interrupt. */
- QUIT;
-
- /* If minibuffer on and echo area in use, wait 2 sec and redraw
- minibuffer. Treat a ^G here as a command, not an interrupt.
- */
- if (minibuf_level > 0 && echo_area_active (selected_frame ()))
- {
- /* Bind inhibit-quit to t so that C-g gets read in
- rather than quitting back to the minibuffer. */
- int count = specpdl_depth ();
- specbind (Qinhibit_quit, Qt);
- Fsit_for (make_number (2), Qnil);
- clear_echo_area (selected_frame (), Qnil, 0);
- unbind_to (count, Qnil);
- }
-
- Fnext_event (event, Qnil);
- /* If ^G was typed while emacs was reading input from the user, then
- Fnext_event() will have read it as a normal event and
- next_event_internal() will have set Vquit_flag. We reset this
- so that the ^G is treated as just another key. This is strange,
- but it is what emacs 18 did.
-
- Do not call check_quit() here. */
- Vquit_flag = Qnil;
- Fdispatch_event (event);
- }
- UNGCPRO;
- return Qnil;
- }
-
-
- /**********************************************************************/
- /* Miscellaneous low-level functions */
- /**********************************************************************/
-
- DEFUN ("open-dribble-file", Fopen_dribble_file, Sopen_dribble_file, 1, 1,
- "FOpen dribble file: ",
- "Start writing all keyboard characters to FILE.")
- (file)
- Lisp_Object file;
- {
- /* This function can GC */
- if (dribble)
- fclose (dribble);
- dribble = 0;
- if (!NILP (file))
- {
- file = Fexpand_file_name (file, Qnil);
- dribble = fopen ((char *) string_data (XSTRING (file)), "w");
- }
- return Qnil;
- }
-
-
- static Lisp_Object
- unwind_init_sys_modes (Lisp_Object device)
- {
- reinit_initial_device ();
-
- if (!no_redraw_on_reenter)
- {
- if (DEVICEP (device) && DEVICE_LIVE_P (XDEVICE (device)))
- MARK_FRAME_CHANGED (XFRAME (DEVICE_SELECTED_FRAME (XDEVICE (device))));
- }
- return Qnil;
- }
-
- DEFUN ("suspend-emacs", Fsuspend_emacs, Ssuspend_emacs, 0, 1, "",
- "Stop Emacs and return to superior process. You can resume later.\n\
- On systems that don't have job control, run a subshell instead.\n\n\
- If optional arg STUFFSTRING is non-nil, its characters are stuffed\n\
- to be read as terminal input by Emacs's superior shell.\n\
- Before suspending, if `suspend-hook' is bound and value is non-nil\n\
- call the value as a function of no args. Don't suspend if it returns non-nil.\n\
- Otherwise, suspend normally and after resumption call\n\
- `suspend-resume-hook' if that is bound and non-nil.\n\
- \n\
- Some operating systems cannot stop the Emacs process and resume it later.\n\
- On such systems, Emacs will start a subshell and wait for it to exit.")
- (stuffstring)
- Lisp_Object stuffstring;
- {
- Lisp_Object tem;
- int speccount = specpdl_depth ();
- struct gcpro gcpro1;
-
- if (!NILP (stuffstring))
- CHECK_STRING (stuffstring, 0);
- GCPRO1 (stuffstring);
-
- /* There used to be a check that the initial device is TTY.
- This is bogus. Even checking to see whether any device
- is a controlling terminal is not correct -- maybe
- the user used the -t option or something. If we want to
- suspend, then we suspend. Period. */
-
- /* Call value of suspend-hook
- if it is bound and value is non-nil. */
- if (!NILP (Vrun_hooks))
- {
- tem = call1 (Vrun_hooks, Qsuspend_hook);
- if (!EQ (tem, Qnil)) return Qnil;
- }
-
- reset_initial_device ();
- /* sys_suspend can get an error if it tries to fork a subshell
- and the system resources aren't available for that. */
- record_unwind_protect (unwind_init_sys_modes, Vcontrolling_terminal);
- stuff_buffered_input (stuffstring);
- sys_suspend ();
- /* the device is un-reset inside of the unwind-protect. */
- unbind_to (speccount, Qnil);
-
- /* Call value of suspend-resume-hook
- if it is bound and value is non-nil. */
- if (!NILP (Vrun_hooks))
- call1 (Vrun_hooks, Qsuspend_resume_hook);
-
- UNGCPRO;
- return Qnil;
- }
-
- /* If STUFFSTRING is a string, stuff its contents as pending terminal input.
- Then in any case stuff anything Emacs has read ahead and not used. */
-
- void
- stuff_buffered_input (Lisp_Object stuffstring)
- {
- /* stuff_char works only in BSD, versions 4.2 and up. */
- #if defined (BSD)
- unsigned char *p;
-
- if (!DEVICEP (Vcontrolling_terminal) ||
- !DEVICE_LIVE_P (XDEVICE (Vcontrolling_terminal)))
- return;
-
- if (STRINGP (stuffstring))
- {
- int count;
-
- p = (unsigned char *) string_ext_data (XSTRING (stuffstring));
- count = string_ext_length (XSTRING (stuffstring));
- while (count-- > 0)
- stuff_char (XDEVICE (Vcontrolling_terminal), *p++);
- stuff_char (XDEVICE (Vcontrolling_terminal), '\n');
- }
- /* Anything we have read ahead, put back for the shell to read. */
- # if 0 /* oh, who cares about this silliness */
- while (kbd_fetch_ptr != kbd_store_ptr)
- {
- if (kbd_fetch_ptr == kbd_buffer + KBD_BUFFER_SIZE)
- kbd_fetch_ptr = kbd_buffer;
- stuff_char (XDEVICE (Vcontrolling_terminal), *kbd_fetch_ptr++);
- }
- # endif
- #endif /* BSD */
- }
-
- DEFUN ("set-input-mode", Fset_input_mode, Sset_input_mode, 3, 5, 0,
- "Set mode of reading keyboard input.\n\
- First arg is ignored, for backward compatibility.\n\
- Second arg FLOW non-nil means use ^S/^Q flow control for output to terminal\n\
- (no effect except in CBREAK mode).\n\
- Third arg META t means accept 8-bit input (for a Meta key).\n\
- META nil means ignore the top bit, on the assumption it is parity.\n\
- Otherwise, accept 8-bit input and don't use the top bit for Meta.\n\
- First three arguments only apply to TTY devices.\n\
- Optional fourth arg QUIT if non-nil specifies character to use for quitting.\n\
- Optional fifth arg DEVICE specifies device to make changes to; nil means\n\
- the current device.\n\
- See also `current-input-mode'.")
- (ignored, flow, meta, quit, device)
- Lisp_Object ignored, flow, meta, quit, device;
- {
- struct device *d = get_device (device);
- int meta_key = 1;
-
- if (DEVICE_IS_TTY (d))
- {
- if (NILP (meta))
- meta_key = 0;
- else if (EQ (meta, Qt))
- meta_key = 1;
- else
- meta_key = 2;
- }
-
- if (!NILP (quit))
- {
- CHECK_INT (quit, 3);
- DEVICE_QUIT_CHAR (d) =
- ((unsigned int) XINT (quit)) & (meta_key ? 0377 : 0177);
- }
-
- if (DEVICE_IS_TTY (d))
- {
- reset_one_device (d);
- TTY_FLAGS (d).flow_control = !NILP (flow);
- TTY_FLAGS (d).meta_key = meta_key;
- init_one_device (d);
- }
-
- return Qnil;
- }
-
- DEFUN ("current-input-mode", Fcurrent_input_mode, Scurrent_input_mode, 0, 1, 0,
- "Return information about the way Emacs currently reads keyboard input.\n\
- Optional arg DEVICE specifies device to return information about; nil means\n\
- the current device.\n\
- The value is a list of the form (nil FLOW META QUIT), where\n\
- FLOW is non-nil if Emacs uses ^S/^Q flow control for output to the\n\
- terminal; this does not apply if Emacs uses interrupt-driven input.\n\
- META is t if accepting 8-bit input with 8th bit as Meta flag.\n\
- META nil means ignoring the top bit, on the assumption it is parity.\n\
- META is neither t nor nil if accepting 8-bit input and using\n\
- all 8 bits as the character code.\n\
- QUIT is the character Emacs currently uses to quit.\n\
- FLOW, and META are only meaningful for TTY devices.\n\
- The elements of this list correspond to the arguments of\n\
- `set-input-mode'.")
- (device)
- Lisp_Object device;
- {
- Lisp_Object val[4];
- struct device *d = get_device (device);
-
- val[0] = Qnil;
- val[1] = DEVICE_IS_TTY (d) && TTY_FLAGS (d).flow_control ? Qt : Qnil;
- val[2] = (!DEVICE_IS_TTY (d) || TTY_FLAGS (d).meta_key == 1) ?
- Qt : TTY_FLAGS (d).meta_key == 2 ? make_number (0) : Qnil;
- val[3] = make_number (DEVICE_QUIT_CHAR (d));
-
- return Flist (sizeof (val) / sizeof (val[0]), val);
- }
-
-
- /**********************************************************************/
- /* Initialization */
- /**********************************************************************/
-
- void
- syms_of_keyboard (void)
- {
- defsymbol (&Qcommand_error, "command-error");
- defsymbol (&Qreally_early_error_handler, "really-early-error-handler");
- defsymbol (&Qtop_level, "top-level");
- defsymbol (&Qsuspend_hook, "suspend-hook");
- defsymbol (&Qsuspend_resume_hook, "suspend-resume-hook");
-
- #ifndef LISP_COMMAND_LOOP
- defsubr (&Srecursive_edit);
- #endif
- defsubr (&Sreally_early_error_handler);
- defsubr (&Scommand_loop_1);
-
- defsubr (&Ssuspend_emacs);
- defsubr (&Sopen_dribble_file);
- defsubr (&Sset_input_mode);
- defsubr (&Scurrent_input_mode);
- }
-
- void
- vars_of_keyboard (void)
- {
- DEFVAR_INT ("command-loop-level", &command_loop_level,
- "Number of recursive edits in progress.");
- command_loop_level = 0;
-
- DEFVAR_LISP ("disabled-command-hook", &Vdisabled_command_hook,
- "Value is called instead of any command that is disabled,\n\
- i.e. has a non-nil `disabled' property.");
- Vdisabled_command_hook = intern ("disabled-command-hook");
-
- #ifndef LISP_COMMAND_LOOP
- DEFVAR_LISP ("top-level", &Vtop_level,
- "Form to evaluate when Emacs starts up.\n\
- Useful to set before you dump a modified Emacs.");
- Vtop_level = Qnil;
- #else
- DEFVAR_LISP ("command-loop", &Vcommand_loop,
- "Function or one argument to call to read and process keyboard commands.\n\
- The passed argument specifies whether or not to handle errors.");
- Vcommand_loop = Qnil;
- #endif /* LISP_COMMAND_LOOP */
- }
-
- void
- init_keyboard (void)
- {
- dribble = 0;
- }
-